Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Animation Utilities #177

Open
wants to merge 3 commits into
base: new-animation-api
Choose a base branch
from

Conversation

lucasdinonolte
Copy link
Contributor

@lucasdinonolte lucasdinonolte commented May 17, 2023

This is a little something that was in the back of my head for some time – but it's only for after the new animation API is in.

Context

I've found myself copy & pasting over code to handle non-linear interpolation (aka easing) for animation over and over again. So I had this idea it could be cool if mechanic provided a simple way to use the most common easing functions without having to re-code them yourself.

What this does

This adds a @mechanic-design/transition package that exposes a generic interpolation helper to the user. It also comes with pre-built versions of the most commonly used easing functions for quick access. But users’ can also bring their own easing function if they wanted to.

The transition function is setup as a curried function, to encourage a clean usage based on animation lifecycle events—the transition should be set up when setting up your design function and then in the draw loop you only pull values from it.

Examples

The most basic example, animating a rectangle’s position:

import { transition } from "@mechanic-design/transition";

export const handler = async ({ inputs, frame, done, getCanvas, drawLoop }) => {
  const { width, height } = inputs;

  const { ctx } = getCanvas(width, height);
  const xPos = transition({
    from: width * 0.3,
    to: width * 0.7,
    duration: 2,

    // Allows to set how often the transition should run
    // Defaults to 1
    iterationCount: 10,

    // Defines the direction of the animation
    // forward (0 -> 1)
    // runs the animation in the specified direction
    //
    // reverse (1 -> 0)
    // runs the animation in the reversed direction 
    //
    // alternate (0 -> 1 -> 0 -> 1 -> ...)
    // runs the animation in alternating directions, starting
    // with a forwards run.
    //
    // alternateReverse (1 -> 0 -> -> 0 -> ...)
    // runs the animation in alternating directions, starting
    // with a reversed run.
    //
    // Defaults to forward
    direction: 'alternate',

    // A user can go for one of the pre-built easing functions
    // by referencing its name
    easing: 'easeInOutQuad',
  });

  drawLoop(({ timestamp }) => {
    ctx.clearRect(0, 0, width, height);

    ctx.fillStyle = "blue";
    ctx.fillRect(xPos(timestamp), height / 2 - 50, 100, 100);

    if (timestamp < 2) {
      frame();
    } else {
      done();
    }
  });
};

Using a custom easing function:

import { transition } from "@mechanic-design/transition";

export const handler = async ({ inputs, frame, done, getCanvas, drawLoop }) => {
  const { width, height } = inputs;

  const { ctx } = getCanvas(width, height);
  const xPos = transition({
    from: width * 0.3,
    to: width * 0.7,
    duration: 2,

    // Easing functions are called with a linear t value below 0 and 1
    // and map this value to whatever easing curve you want to approximate
    //
    // The example below maps to a cubic curve
    easing: t => t * t * t
  });

  drawLoop(({ timestamp }) => {
    ctx.clearRect(0, 0, width, height);

    ctx.fillStyle = "blue";
    ctx.fillRect(xPos(timestamp), height / 2 - 50, 100, 100);

    if (timestamp < 2) {
      frame();
    } else {
      done();
    }
  });
};

The transition helper only works with numerical values. You could however still use it to interpolate non numerical values (like color), by using the transition helper to generate the easing curve for you and then passing a normalized transition value to a specific interpolation function. The example shows this

const colorEase = transition({
    from: 0,
    to: 1,
    duration: 2,
    easing: 'easeInOutQuad',
});

drawLoop(({ timestamp }) => {
  // The imaginary colorInterpolator function would be a custom function
  // (user-written or from a library) that interpolates two colors based on
  // a 0–1 value. The transition helper is used here to put the easing curve
  // on the 0–1 scale.
  const color = colorInterpolator(color1, color2, colorEase);

  ctx.fillStyle = color;
});

@netlify
Copy link

netlify bot commented May 17, 2023

Deploy Preview for dsi-logo-maker ready!

Name Link
🔨 Latest commit 564f6e5
🔍 Latest deploy log https://app.netlify.com/sites/dsi-logo-maker/deploys/64649e3d1d53df0008230470
😎 Deploy Preview https://deploy-preview-177--dsi-logo-maker.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

@lucasdinonolte lucasdinonolte changed the title Animation Utilities [WIP] Animation Utilities May 17, 2023
@fdoflorenzano fdoflorenzano changed the base branch from main to new-animation-api May 17, 2023 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant